package com.jackstraw.jack_base.remote_command.service;

import com.jackstraw.jack_base.remote_command.config.JschConfig;
import com.jackstraw.jack_base.remote_command.entity.BeforeAfterEnum;
import com.jackstraw.jack_base.remote_command.entity.Conn;
import com.jackstraw.jack_base.remote_command.entity.InstallProperties;
import com.jackstraw.jack_base.remote_command.entity.JackSoftProperties;
import com.jackstraw.jack_base.remote_command.entity.ModelEnum;
import com.jackstraw.jack_base.remote_command.entity.NonPasswordProperties;
import com.jackstraw.jack_base.util.FileUtil;

import com.jackstraw.jack_base.util.exception.BadRequestException;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.core.io.ResourceLoader;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;


public interface GroupControlService {

    JschService getJschService();

    /**
     * 状态查询
     *
     * @return
     */
    Boolean stats(String softName, String systemName) throws Exception;

    /**
     * 前置状态查询
     *
     * @return
     */
    Boolean beforeStats(String softName, String systemName) throws Exception;

    /**
     * 后置查询
     *
     * @param softName
     * @param systemName
     * @return
     */
    Boolean afterStats(String softName, String systemName) throws Exception;

    /**
     * 启动
     */
    List<String> start(String softName, String systemName) throws Exception;

    /**
     * 前置启动
     */
    List<String> beforeStart(String softName, String systemName) throws Exception;

    /**
     * 后置启动
     */
    List<String> afterStart(String softName, String systemName) throws Exception;

    /**
     * 停止
     */
    List<String> stop(String softName, String systemName) throws Exception;

    /**
     * 前置停止
     */
    List<String> beforeStop(String softName, String systemName) throws Exception;

    /**
     * 后置停止
     */
    List<String> afterStop(String softName, String systemName) throws Exception;

    /**
     * 重启
     */
    List<String> restart(String softName, String systemName) throws Exception;

    /**
     * 前置重启
     */
    List<String> beforeRestart(String softName, String systemName) throws Exception;

    /**
     * 后置重启
     */
    List<String> afterRestart(String softName, String systemName) throws Exception;

    /**
     * 安装
     *
     * @param installProperties
     * @throws Exception
     */
    void install(InstallProperties installProperties) throws Exception;

    /**
     * 判断是否含有脚本
     *
     * @param connName
     * @param installProperties
     * @throws Exception
     */
    void execScript(String connName, InstallProperties installProperties) throws Exception;

    /**
     * 执行前置脚本
     *
     * @param connName
     * @param installProperties
     * @throws Exception
     */
    void execBeforeScript(String connName, InstallProperties installProperties) throws Exception;

    /**
     * 执行脚本文件
     *
     * @param installProperties
     * @throws Exception
     */
    void execDbScript(InstallProperties installProperties) throws Exception;

    /**
     * 执行脚本
     *
     * @param connName
     * @param installScriptPath
     * @throws Exception
     */
    void execScript(String connName, String installScriptPath) throws Exception;

    /**
     * 单节点安装
     *
     * @param installProperties
     * @throws Exception
     */
    void installSingle(InstallProperties installProperties) throws Exception;

    /**
     * 集群安装
     *
     * @param installProperties
     * @throws Exception
     */
    void installCluster(InstallProperties installProperties) throws Exception;

    void uploadConfig(InstallProperties installProperties) throws Exception;

    /**
     * 获取配置文件
     *
     * @return
     */
    Map<String, JackSoftProperties.SoftProperties> getJackSoftPropertiesMap();

    /**
     * 获取配置
     *
     * @return
     */
    JschConfig getJschConfig();

    /**
     * 获取ResourceLoader
     *
     * @return
     */
    ResourceLoader getResourceLoader();

    /**
     * 设置免密登录
     *
     * @param nonPasswordProperties
     */
    void nonPassword(NonPasswordProperties nonPasswordProperties) throws Exception;

    /**
     * 获取锁
     *
     * @return
     */
    Lock getLock();

    /**
     * jack 启动
     *
     * @param softName
     * @param systemName
     */
    default List<String> jackStart(String softName, String systemName) throws Exception {
        List<String> response = new ArrayList<>();
        if (!this.beforeStats(softName, systemName)) {
            response.addAll(this.beforeStart(softName, systemName));
        }
        if (!this.stats(softName, systemName)) {
            response.addAll(this.start(softName, systemName));
        }
        if (!this.afterStats(softName, systemName)) {
            response.addAll(this.afterStart(softName, systemName));
        }

        return response;
    }

    /**
     * jack 状态
     *
     * @param softName
     * @param systemName
     * @return
     */
    default Boolean jackStats(String softName, String systemName) throws Exception {
        return this.beforeStats(softName, systemName) && this.stats(softName, systemName) && this.afterStats(softName, systemName);
    }

    /**
     * jack 停止
     *
     * @param softName
     * @param systemName
     */
    default List<String> jackStop(String softName, String systemName) throws Exception {
        List<String> response = new ArrayList<>();
        if (this.stats(softName, systemName)) {
            response.addAll(this.stop(softName, systemName));
        }
        if (this.beforeStats(softName, systemName)) {
            response.addAll(this.beforeStop(softName, systemName));
        }
        if (this.afterStats(softName, systemName)) {
            response.addAll(this.afterStop(softName, systemName));
        }
        return response;
    }

    /**
     * jack 重启
     *
     * @param softName
     * @param systemName
     */
    default List<String> jackReStart(String softName, String systemName) throws Exception {
        List<String> response = new ArrayList<>();
        response.addAll(this.beforeRestart(softName, systemName));
        response.addAll(this.restart(softName, systemName));
        response.addAll(this.afterRestart(softName, systemName));
        return response;
    }

    default String concatSoftName(String softName, String systemName) {
        return StringUtils.isEmpty(systemName) ? softName :
                softName.endsWith(systemName) ?
                        softName : softName.concat("-").concat(systemName);
    }


    /**
     * 拼接启动命令
     *
     * @param containerName
     * @return
     */
    default String concatStart(String containerName) {
        return " docker start ".concat(containerName);
    }

    /**
     * 拼接停止命令
     *
     * @param containerName
     * @return
     */
    default String concatStop(String containerName) {
        return " docker stop ".concat(containerName);
    }

    /**
     * 拼接重启命令
     *
     * @param containerName
     * @return
     */
    default String concatReStart(String containerName) {
        return " docker restart ".concat(containerName);
    }

    /**
     * 拼接查询状态命令
     *
     * @param containerName
     * @return
     */
    default String concatStats(String containerName) {
        return " docker inspect --format '{{.State.Running}}' ".concat(containerName);
    }

    /**
     * 执行命令
     *
     * @param beforeAfterEnum
     * @param modelEnum
     * @param connName
     * @param jackSoftProperties
     * @return
     */
    default List<String> execOtherCmd(BeforeAfterEnum beforeAfterEnum, ModelEnum modelEnum, String connName, JackSoftProperties.SoftProperties jackSoftProperties) throws Exception {
        return this.execOtherCmd(this.getModelCmdStatus(beforeAfterEnum, modelEnum), connName, jackSoftProperties);
    }

    /**
     * 执行命令
     *
     * @param modelCmdStatus
     * @param connName
     * @param jackSoftProperties
     * @return
     */
    default List<String> execOtherCmd(String modelCmdStatus, String connName, JackSoftProperties.SoftProperties jackSoftProperties) throws Exception {
        List<String> response = new ArrayList<>();
        Map<String, Map<String, List<String>>> modelCmdStatusMap = jackSoftProperties.getModelCmdStatusMap();
        if (ObjectUtils.isEmpty(modelCmdStatusMap) || modelCmdStatusMap.size() == 0) {
            return response;
        }
        Map<String, List<String>> cmdStatusMap = modelCmdStatusMap.get(modelCmdStatus);
        if (ObjectUtils.isEmpty(cmdStatusMap) || cmdStatusMap.size() == 0) {
            return response;
        }
        List<String> cmdList = cmdStatusMap.get(connName);
        if (ObjectUtils.isEmpty(cmdList) || cmdList.size() == 0) {
            return response;
        }
        for (String cmd : cmdList) {
            response.add(this.getJschService().execShell(Conn.buildExec(connName), cmd));
        }
        return response;
    }

    default String getModelCmdStatus(BeforeAfterEnum beforeAfterEnum, ModelEnum modelEnum) {
        return beforeAfterEnum.getCode().concat("-").concat(modelEnum.getCode());
    }

    /**
     * 将IO流读取成字符串
     *
     * @param directory 文件路径
     * @return
     */
    default String readInputStream(String directory) throws Exception {
        return this.readInputStream(directory, Charset.defaultCharset());
    }

    /**
     * 将IO流读取成字符串
     *
     * @param file file
     * @return
     */
    default String readInputStream(File file) throws Exception {
        return this.readInputStream(file, Charset.defaultCharset());
    }


    /**
     * 将IO流读取成字符串
     *
     * @param inputStream io流
     * @return
     */
    default String readInputStream(InputStream inputStream) throws Exception {
        return this.readInputStream(inputStream, Charset.defaultCharset());
    }

    /**
     * 将IO流读取成字符串
     *
     * @param directory 要读的文件路径
     * @param charset   字符集
     * @return
     */
    default String readInputStream(String directory, Charset charset) throws Exception {
        return this.readInputStream(new File(directory), charset);
    }

    /**
     * 将IO流读取成字符串
     *
     * @param file    file
     * @param charset 字符集
     * @return
     */
    default String readInputStream(File file, Charset charset) throws Exception {
        if (!file.isFile()) {
            throw new BadRequestException("3400000001", "无法将非文件读取为字符串");
        }
        return this.readInputStream(new FileInputStream(file), charset);
    }

    /**
     * 将IO流读取成字符串
     *
     * @param inputStream io流
     * @param charset     字符集
     * @return
     */
    default String readInputStream(InputStream inputStream, Charset charset) throws Exception {
        return FileUtil.IoUtilByHutool.readNote(inputStream, charset);
    }


    /**
     * newCondition
     *
     * @return
     */
    default Condition newCondition() {
        return this.getLock().newCondition();
    }
}
